<html>
    <head>
        <title>队列----一系列的状态更新</title>
    </head>
    <body>
        <script>
            // 队列---一些列的状态更新

                    // 本章最重要的一句话是  ：   "状态设置函数"的参数是一个"状态修改函数的声明"或者"一个值"(一个值也可以看做是一个"函数声明" ，这无论是在js中还是C#中都成立)
                    
                    /*
                        设置状态变量将使另一个渲染进入排队。
                        但有时候，你可能希望在下一次渲染之前"对状态变量执行多个操作"。
                        为此，你需要了解一下React如何"批处理状态更新的"
                    */


                    // 一、React 批量状态更新（一次事件处理程序，更新了多个状态变量）
                            /*
                                你可能希望单击"+3"按钮会让计数器递增3次，因为调用了3次。
                                但是，你可能还记得上一节中 "每个渲染器的状态值都是固定的"，以第一个渲染事件处理程序中的 number 的值始终是 0，无论你调用 setNumber(1) 多少次。


                                但这里还有另外一个因素在起作用:
                                        "在处理状态更新前，React会等到事件处理程序的所有代码都执行完。"  
                                        这就是为什么重新渲染只会发生在所有这些setNumber调用之后。


                                这可能会让你想起在餐厅点菜的服务员，他不会当你点完第一个才就跑去厨房！ 而是，它等你完成点菜，点完所有的菜才会把菜单送给厨房。
                                这使你可以更新多个状态变量---甚至来自多个组件，而不会触发太多次渲染。但这也意味着在事件处理程序以及其中的任何代码执行完成前"不会重新渲染"。
                                这种行为(也称为"批处理")会使你的React应用运行的更快。
                                它还避免处理只有部分变量已更新的令人困惑的 “half-finished” 渲染。

                                另外，React不会批量处理多个有意事件(例如多次点击)----每次点击都是单独处理的。
                            
                            */ 


                    // 二、在下次渲染之前多次更新相同的状态（一次事件处理程序，多次更改同一个状态变量）
                            /*
                                这是一个不常见的用例，但是如果你想在下一次渲染之前多次更新同一个状态变量，而不是像 setNumber(number+1)那样传递下一个状态值。
                                你可以"状态设置函数"传递一个"根据前一个状态值计算下一个状态值的函数"到"队列"中。
                                这样就是告诉React用"用状态值来做某事"而不是仅仅是想要替换状态值。
                            */
                                // eg:  
                                    export default function Counter(){
                                        const [number,setNumber] =useState(0);

                                        return(
                                            <>
                                                <h1>{number}</h1>
                                                <button onClick={()=>{
                                                    setNumber(n=>n+1);  // 这里 n+1 被称为"更新器函数"，注意他是一个函数，入参 n 就是上一个状态值
                                                    setNumber(n=>n+1);
                                                    setNumber(n=>n+1);
                                                }}>+3</button>
                                            </>
                                        );
                                    }

                            /*
                                这里，n=>n+1 被称为"更新器函数"。

                                当你将其传递给状态设置函数时：
                                    1、在事件处理程序中的所有其他代码运行之后，React将此函数排队等待处理。
                                    2、在下次渲染期间，React"遍历队列" 并为你提供最终的更新状态。

                                        于是形成下面的队列：
                                                setNumber(n => n + 1);
                                                setNumber(n => n + 1);
                                                setNumber(n => n + 1);

                                        以下是React在执行事件处理程序时如何处理这些代码：
                                               setNumber(n => n + 1)：n => n + 1 是一个函数。React 将其添加到队列中。
                                               setNumber(n => n + 1)：n => n + 1 是一个函数。React 将其添加到队列中。
                                               setNumber(n => n + 1)：n => n + 1 是一个函数。React 将其添加到队列中。

                                        当你在下一次渲染期间调用useState时(组件函数调用useState时)，React会遍历队列。

                                        看到这，你能想象这个"队列"是怎么形成的吗：
                                            就是对个 n=>n+1 这样的"状态更新函数"收尾相连形成的一个队列。 
                                            最开始的入参就是上一个状态快照中的状态值，然后前面"状态更新函数"的返回值作为下一个"状态更新函数"的入参，以此类推，如同人体蜈蚣一样。

                                        


                            */

                    // 三、在替换状态后更新状态会发生什么
                              /*
                                    这个事件处理程序怎么样？

                                         <button onClick={()=>{
                                            setNumber(number+5);
                                            setNumber(n=>n+2);
                                         }}/>

                                    以下是此事件处理程序告诉 React 执行的操作：
                                            setNumber(number + 5)：number 是 0，所以 setNumber(0 + 5)。React 将“替换为 5”添加到其队列中。
                                            setNumber(n => n + 1)：n => n + 1 是一个更新函数。React 将该函数添加到它的队列中。

                                            在下一次渲染期间，React遍历队列：

                                                排队更新        n          返回

                                                "替换为 0+5"    0(未使用)   5

                                                n=>n+1          5           6

                                            React 将6作为下一次渲染形成的状态快照中 number的值，并从 useState钩子返回它。

                                            注意： setNumber(5) 其实就是 setNumber(n=>5) 的简写形式，React中其实有默认的状态更新函数，即 n=>5 这种形式。
                                                   如果使用 setNumber(n=>n+5),其实 setNumer变量的值就是 n=>n+5这个函数声明。

                                                   所以 setNumber(状态设置函数表达式) 变量的值，就是一个函数声明，或者一个值(一个值也可以看做是函数声明)
                                                   所以，setNumber (状态设置函数表达式)的参数，就是一个函数声明或者一个值。

                              */


                    // 四、如果在更新状态后替换它会发生什么？
                            /*
                                     <button onClick={() => {
                                        setNumber(number + 5);
                                        setNumber(n => n + 1);
                                        setNumber(42);
                                     }}>    

                                     以下是 React 在执行此事件处理程序时如何处理这些代码行：
                                                setNumber(number + 5)：number 是 0，所以 setNumber(0 + 5)。React 将“替换为 5”添加到其队列中。
                                                setNumber(n => n + 1)：n => n + 1 是一个更新函数。React 将该函数添加到它的队列中。
                                                setNumber(42)：React 将“替换为 42”添加到其队列中。

                                    在下一次渲染期间，React遍历队列：
                                             
                                            排队更新      n          返回
                                            n=> 0+5      5
                                            n=>n+1       5           6
                                            n=>42        6(未使用)    42     
                                    
                                    还是和上面一样，你把替换转化为　n=>7  或 n=>1+2 (一个不使用入参的更新函数)
                                                  把更新理解为 n=>n+1 (一个使用入参的更新函数)  
                                                  一定不会出现任何问题！！
                            */



                // 本章最重要的一句话是  ：   "状态设置函数"的参数是一个"状态修改函数的声明"或者"一个值"(一个值也可以看做是一个"函数声明" ，这无论是在js中还是C#中都成立)
        </script>
    </body>
</html>